#Requires AutoHotkey v2.0

BMPFromHwnd(&hBitmap, hwnd, w, h, x, y) {
  hSourceDC := hwnd ? DllCall('GetDC', 'ptr', hwnd) : DllCall('GetDC', 'ptr', 0)
  hMemDC := DllCall("CreateCompatibleDC", "Ptr", 0)
  hBitmap := DllCall("CreateCompatibleBitmap"
    , "ptr", hSourceDC
    , "int", w
    , "int", h)
  hOldBitmap := DllCall("SelectObject"
    , "Ptr", hMemDC
    , "Ptr", hBitmap)
  DllCall("BitBlt"
    , "Ptr", hMemDC
    , "int", 0
    , "int", 0
    , "int", w
    , "int", h
    , "Ptr", hSourceDC
    , "int", x
    , "int", y
    , "uint", 0xCC0020)
  hOldBitmap := DllCall("SelectObject"
    , "Ptr", hMemDC
    , "Ptr", hOldBitmap)
  DllCall('DeleteDC', 'ptr', hMemDC)
  DllCall('ReleaseDC', 'int', 0, 'ptr', hSourceDC)
}

CopyHBM(hBM1, hBM2, w1, h1, x1, y1, x2, y2) {
  mDC1 := DllCall("CreateCompatibleDC", "Ptr", 0)
  oBM1 := DllCall("SelectObject"
    , "Ptr", mDC1
    , "Ptr", hBM1)
  mDC2 := DllCall("CreateCompatibleDC", "Ptr", 0)
  oBM2 := DllCall("SelectObject"
    , "Ptr", mDC2
    , "Ptr", hBM2)
  DllCall("BitBlt"
    , "Ptr", mDC1
    , "int", x1
    , "int", x2
    , "int", w1
    , "int", h1
    , "Ptr", mDC2
    , "int", x2
    , "int", y2
    , "uint", 0xCC0020)
  DllCall("SelectObject"
    , "Ptr", mDC1
    , "Ptr", oBM1)
  DllCall("DeleteDC", "Ptr", mDC1)
  DllCall("SelectObject"
    , "Ptr", mDC2
    , "Ptr", oBM2)
  DllCall("DeleteDC", "Ptr", mDC2)
}

DisplayBitmap(path, hwnd, w1, h1, x1 := 0, y1 := 0, x2 := 0, y2 := 0) {
  rbf := FileRead(path, 'Raw')
  ReadBMPInfo(rbf, &width, &height, &pBits, &bfh)

  hDC := DllCall("GetDC", 'UInt', hwnd) ; Fix Me
  ; hDC := CreateCompatibleDC(hwnd)
  DllCall('StretchDIBits'
    , 'ptr', hDC, 'int', x1, 'int', y1, 'int', w1, 'int', h1, 'int', x2, 'int', y2
    , 'int', width, 'int', height
    , 'ptr', pBits
    , 'ptr', bfh.Ptr
    , 'int', 0x00, "uint", 0xCC0020)
  DllCall('ReleaseDC', 'int', 0, 'uint', hDC)
}

GetBitmapWH(hBM, &w, &h) {
  bm := Buffer(size := (A_PtrSize = 8 ? 32 : 24))
  DllCall("GetObject"
    , "Ptr", hBM
    , "int", size
    , "Ptr", bm)
  w := NumGet(bm, 4, "int")
  h := Abs(NumGet(bm, 8, "int"))
}

ReadBMPWH(path, &width, &height) {
  rbf := FileRead(path, 'Raw')
  bfType := NumGet(rbf, 'short')
  if bfType != (Ord('B') | (Ord('M') << 8))
    throw Error('文件类型错误')
  bitCount := NumGet(rbf, 28, 'short')
  width := NumGet(rbf, 18, 'int')
  height := NumGet(rbf, 22, 'int')
}

ReadBMPInfo(rbf, &width, &height, &pBits, &bfh, &dataSize := unset) {
  bfType := NumGet(rbf, 'short')
  if bfType != (Ord('B') | (Ord('M') << 8))
    throw Error('文件类型错误')

  bh := Buffer(14, 0) ; 文件头
  NumPut('short', bfType, bh) ; bfType
  NumPut('uint', NumGet(rbf, 2, 'uint'), bh) ; bfSize
  NumPut('uint', NumGet(rbf, 10, 'uint'), bh) ; bfOffBits

  width := NumGet(rbf, 18, 'int')
  height := NumGet(rbf, 22, 'int')
  bitCount := NumGet(rbf, 28, 'short')

  bfh := Buffer(40, 0) ; 位图信息头
  NumPut('int', 40, bfh) ; biSize
  NumPut('int', width, bfh, 4) ; biWidth
  NumPut('int', height, bfh, 8) ; biHeight
  NumPut('short', 1, bfh, 12) ; biPlanes
  NumPut('short', bitCount, bfh, 14) ; biBitCount

  ; (额外数据)
  bytePerPixel := bitCount / 8
  lineSize := (width * 3 + 3) & (~3)
  IsSet(dataSize) && dataSize := lineSize * height

  pBits := rbf.Ptr + 54
}